package com.chenl.provider.DEMOS.重复点击处理.redis版本;

import com.alibaba.fastjson2.JSONObject;
import com.chenl.provider.DEMOS.重复点击处理.LocalLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 防重提交,redis版本
 */
@Aspect
@Configuration
@Slf4j
public class LockMethodAspect {
    @Autowired
    BeanFactory beanFactory;

    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    private static final ExpressionParser PARSER = new SpelExpressionParser();

    @Resource(name = "MyRedisTemplate")
    RedisTemplate redisTemplate;

    @Before("@annotation(com.chenl.provider.DEMOS.重复点击处理.LocalLock)")
    public void interceptor(JoinPoint joinPoint){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LocalLock localLock = method.getAnnotation(LocalLock.class);
        long expire = localLock.expire();
        TimeUnit timeUnit = localLock.expireUnit();
        String key = getKey(localLock.key(),method, joinPoint.getArgs());
        System.out.println("key:"+key);
//        String keyWrapper = "LocalLock:"+ localLock.message() + ":" + key;
        String keyWrapper = "LocalLock:"+ request.getRequestURI()+"|"+ localLock.message() + ":" + key;
        System.out.println("keyWrapper:"+keyWrapper);
        if(StringUtils.isNotBlank(keyWrapper)){
            if(redisTemplate.opsForValue().get(keyWrapper)!= null){
                log.error("请勿重复请求---key:{}",keyWrapper);
                log.error("请勿重复请求---joinPoint.getArgs():{}",joinPoint.getArgs());
                throw new RuntimeException("请勿重复点击！");

            }
            redisTemplate.opsForValue().set(keyWrapper,keyWrapper,expire,timeUnit);
        }
    }

    private String getKey(String keyExpress, Method method, Object[] args){
//        return JSONObject.toJSONString(args);
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        Parameter[] parameters = method.getParameters();
        for(int i = 0; i < parameters.length; i++){
            context.setVariable(parameters[i].getName(), args[i]);
        }
        return JSONObject.toJSONString(parser.parseExpression(keyExpress).getValue(context));
    }

    protected String getKeys(String[] definitionKeys, Method method, Object[] parameterValues) {
         BeanResolver beanResolver= new BeanFactoryResolver(beanFactory);;
        StandardEvaluationContext context = new MethodBasedEvaluationContext((Object)null, method, parameterValues, NAME_DISCOVERER);
        context.setBeanResolver(beanResolver);
        List<Object> definitionKeyList = new ArrayList(definitionKeys.length);
        String[] var6 = definitionKeys;
        int var7 = definitionKeys.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            String definitionKey = var6[var8];
            if (definitionKey != null && !definitionKey.isEmpty()) {
                Object key = PARSER.parseExpression(definitionKey).getValue(context, Object.class);
                definitionKeyList.add(key);
            }
        }

        return org.springframework.util.StringUtils.collectionToDelimitedString(definitionKeyList, ".", "", "");
    }
}